home *** CD-ROM | disk | FTP | other *** search
/ PD ROM 1 / PD ROM Volume I - Macintosh Software from BMUG (1988).iso / Programming / Programming Tools / Turbo Pascal / Utilities / DEARC5.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1987-06-16  |  23.5 KB  |  969 lines  |  [TEXT/ttxt]

  1. {$R-}
  2.  
  3. program dearc512;
  4.  
  5. { DEARC.PAS - Program to extract all files from an archive created by version
  6.   5.12 or earlier of the ARC utility.
  7.  
  8.   ARC is COPYRIGHT 1985 by System Enhancement Associates.
  9.  
  10.   This program requires Turbo Pascal for the Mac Version 1.00.
  11.  
  12.   Usage:
  13.  
  14.      Open or double-click the DEARC application.
  15.  
  16.  
  17.    *** ORIGINAL AUTHOR UNKNOWN ***
  18.  
  19.   Version 1.01 - 10/19/85. Changed end-of-file processing to, hopefully, be
  20.                            more compatible with CPM (whatever that is).
  21.   Version 1.01A - 12/19/85 By Roy Collins
  22.                            Mail: TechMail BBS @ 703-430-2535
  23.                                  - or -
  24.                                  P.O.Box 1192, Leesburg, Va 22075
  25.                            Modified V1.01 to work with Turbo Pascal Version 2
  26.                            Added functions ARGC (argument count) and ARGV
  27.                            (argument value)
  28.                            Modified all references to "EXIT" command to be
  29.                            GOTO EXIT, with EXIT defined as a LABEL, at the
  30.                            end of the function/procedure involved.
  31.                            Will not accept path names - archives must be in
  32.                            the current directory.
  33.   Version 2.00 - 6/11/86   By David W. Carroll
  34.                            Mail: High Sierra RBBS-PC @ 209/296-3534
  35.                            Now supports ARC version 5.12 files, compression
  36.                            types 7 and 8.
  37.  
  38.   Version m2.00 - 87/03/22 By Mike Babulic.
  39.                            Compuserve ID: 72307,314
  40.                            A fast & dirty port to Macintosh Turbo Pascal.
  41.                            Someone should "Macintize" this properly by using
  42.                            "ALERT"s for the error messages, an "About Dearc..."
  43.                            menu item & use CountAppFiles (etc.) to open the
  44.                            files to be "dearced". I may get around to it if I 
  45.                            find the time.
  46. }
  47.  
  48. {$U FileUt}
  49. USES MemTypes,QuickDraw,OSIntf,ToolIntf,PackIntf,FileUt;
  50.  
  51. function Num2String(n:LongInt):str255;
  52.   var s : str255;
  53.   begin
  54.     NumToString(n,s);
  55.     Num2String := s;
  56.   end;
  57.  
  58. (************ Useful utility to make stuffing easier ***************)
  59.  
  60. var StuffPos : LongInt;
  61.  
  62. procedure StuffIt(p:Ptr; s:Str255);
  63.   begin
  64.     StuffHex(p,s);
  65.     StuffPos := Length(s) shr 1 + LongInt(p);
  66.   end;
  67.  
  68. procedure StuffMore(s:Str255);
  69.   begin
  70.     StuffHex(Ptr(StuffPos),s);
  71.     StuffPos := Length(s) shr 1 + StuffPos;
  72.   end;
  73.   
  74. (*******************************************************************)
  75.  
  76. const BLOCKSIZE = 128;
  77.       arcmarc   = 26;              { special archive marker }
  78.       arcver    = 8;               { max archive header version code }
  79.       strlen    = 100;             { standard string length }
  80.       fnlen     = 12;              { file name length - 1 }
  81.  
  82. var  crctab : array [0..255] of integer; {MGB 86/02/28}
  83.  
  84. procedure init_crctab;
  85. begin
  86.     StuffIt(@crctab,'0000C0C1C1810140C30103C00280C241');
  87.     StuffMore('C60106C00780C7410500C5C1C4810440');
  88.     StuffMore('CC010CC00D80CD410F00CFC1CE810E40');
  89.     StuffMore('0A00CAC1CB810B40C90109C00880C841');
  90.     StuffMore('D80118C01980D9411B00DBC1DA811A40');
  91.     StuffMore('1E00DEC1DF811F40DD011DC01C80DC41');
  92.     StuffMore('1400D4C1D5811540D70117C01680D641');
  93.     StuffMore('D20112C01380D3411100D1C1D0811040');
  94.     StuffMore('F00130C03180F1413300F3C1F2813240');
  95.     StuffMore('3600F6C1F7813740F50135C03480F441');
  96.     StuffMore('3C00FCC1FD813D40FF013FC03E80FE41');
  97.     StuffMore('FA013AC03B80FB413900F9C1F8813840');
  98.     StuffMore('2800E8C1E9812940EB012BC02A80EA41');
  99.     StuffMore('EE012EC02F80EF412D00EDC1EC812C40');
  100.     StuffMore('E40124C02580E5412700E7C1E6812640');
  101.     StuffMore('2200E2C1E3812340E10121C02080E041');
  102.     StuffMore('A00160C06180A1416300A3C1A2816240');
  103.     StuffMore('6600A6C1A7816740A50165C06480A441');
  104.     StuffMore('6C00ACC1AD816D40AF016FC06E80AE41');
  105.     StuffMore('AA016AC06B80AB416900A9C1A8816840');
  106.     StuffMore('7800B8C1B9817940BB017BC07A80BA41');
  107.     StuffMore('BE017EC07F80BF417D00BDC1BC817C40');
  108.     StuffMore('B40174C07580B5417700B7C1B6817640');
  109.     StuffMore('7200B2C1B3817340B10171C07080B041');
  110.     StuffMore('500090C191815140930153C052809241');
  111.     StuffMore('960156C057809741550095C194815440');
  112.     StuffMore('9C015CC05D809D415F009FC19E815E40');
  113.     StuffMore('5A009AC19B815B40990159C058809841');
  114.     StuffMore('880148C0498089414B008BC18A814A40');
  115.     StuffMore('4E008EC18F814F408D014DC04C808C41');
  116.     StuffMore('440084C185814540870147C046808641');
  117.     StuffMore('820142C043808341410081C180814040');
  118.   end;
  119.     
  120. type long    = LongInt;
  121.               (*record           { used to simulate long (4 byte) integers }
  122.                  l, h : integer
  123.                end;*)
  124.  
  125. (***** Useful utility to convert 8086 integers to 68000 format ****)
  126.  
  127. function Int86(i:integer):integer;
  128.   begin
  129.     Int86 := swap(i);
  130.   end;
  131.   
  132. function Long86(i:Long):LongInt;
  133.   type Long = record h,l :integer end;
  134.   var t : integer;
  135.   begin
  136.     with long(i) do begin
  137.       h := swap(h); l := swap(l);
  138.     end;
  139.     Long86 := swapword(i);
  140.   end;
  141.  
  142. (******************************************************************)
  143.                
  144. type strtype = string[strlen];
  145.      fntype  = packed array [0..fnlen] of char;
  146.      buftype = packed array [1..BLOCKSIZE] of byte;
  147.      heads   = packed record
  148.                  name   : fntype;
  149.                  size   : long;
  150.                  date   : integer;
  151.                  time   : integer;
  152.                  crc    : integer;
  153.                  length : long
  154.                end;
  155.  
  156. var hdrver   : byte;
  157.     arcfile  : UntypedFile;
  158.     arcbuf   : buftype;
  159.     arcname  : strtype;
  160.     arcptr   : integer;
  161.     endfile  : boolean;
  162.  
  163.     extfile  : Text;
  164.     extname  : strtype;
  165.  
  166. { definitions for unpack }
  167.  
  168. const DLE = $90;
  169.  
  170. var state  : (NOHIST, INREP);
  171.     crcval : integer;
  172.     size   : LongInt;
  173.     lastc  : integer;
  174.  
  175. { definitions for unsqueeze }
  176.  
  177. const ERROR   = -1;
  178.       SPEOF   = 256;
  179.       NUMVALS = 256;               { 1 less than the number of values }
  180.  
  181. type nd = record
  182.             child : packed array [0..1] of integer
  183.           end;
  184.  
  185. var node     : packed array [0..NUMVALS] of nd;
  186.     bpos     : integer;
  187.     curin    : integer;
  188.     numnodes : integer;
  189.  
  190. { definitions for uncrunch }
  191.  
  192. const TABSIZE   = 4096;
  193.       TABSIZEM1 = 4095;
  194.       NO_PRED   = $FFFF;
  195.       EMPTY     = $FFFF;
  196.  
  197. type entry = PACKED record
  198.                used         : boolean;
  199.                next         : integer;
  200.                predecessor  : integer;
  201.                follower     : byte;
  202.              end;
  203.  
  204. var stack       : packed array [0..TABSIZEM1] of byte;
  205.     sp          : integer;
  206.   type string_tab_type = packed array [0..TABSIZEM1] of entry;
  207.        string_tab_ptr = ^string_tab_type;
  208. var  string_tab  : string_tab_ptr;
  209.  
  210. var code_count : integer;
  211.     code       : integer;
  212.     firstc     : boolean;
  213.     oldcode    : integer;
  214.     finchar    : integer;
  215.     inbuf      : integer;
  216.     outbuf     : integer;
  217.     newhash    : boolean;
  218.  
  219. { definitions for dynamic uncrunch }
  220.  
  221. const
  222.   BITS = 12;
  223.   HSIZE = 5003;
  224.   INIT_BITS = 9;
  225.   FIRST = 257;
  226.   CLEAR = 256;
  227.   HSIZEM1 = 5002;
  228.   BITSM1 = 11;
  229.  
  230. var
  231.   RMASK : packed array[0..8] of byte;{MGB 87/02/28 =
  232.   ($00, $01, $03, $07, $0f, $1f, $3f, $7f, $ff);}
  233.  
  234. type
  235.   prefix_type = packed array[0..HSIZEM1] of integer;
  236.   suffix_type = packed array[0..TABSIZEM1] of byte;
  237.  
  238. var
  239.   n_bits,
  240.   maxcode : integer;
  241.   prefix : ^prefix_type;
  242.   suffix : ^suffix_type;
  243.   buf : packed array[0..BITS] of byte;
  244.     {MGB 87/03/22 was origionally [0..BITSM1]
  245.        BUG WAS NOT DETECTED because of $R- (range checking was turned off)}
  246.   clear_flg : integer;
  247.   stack1 : packed array[0..HSIZEM1] of byte;
  248.   free_ent : integer;
  249.   maxcodemax : integer;
  250.   offset, sizex : integer;
  251.   firstch : boolean;
  252.  
  253. procedure abort(s : strtype);
  254. { terminate the program with an error message }
  255. begin
  256.   writeln('ABORT: ', s);
  257.   close(arcfile);
  258.   close(extfile);
  259.   repeat until keypressed;
  260.   halt;
  261. end; (* proc abort *)
  262.  
  263. function fn_to_str(var fn : fntype) : strtype;
  264. { convert strings from C format (trailing 0) to Turbo Pascal format (leading
  265.     length byte). }
  266. var s : strtype;
  267.     i : integer;
  268. begin
  269.   s := '';
  270.   i := 0;
  271.   while fn[i] <> #0 do begin
  272.     s := s + fn[i];
  273.     i := i + 1
  274.     end;
  275.   fn_to_str := s
  276. end; (* func fn_to_str *)
  277.  
  278. procedure Read_Block;
  279. { read a block from the archive file }
  280.   var blocksRead,nd,pos : LongInt;
  281. begin
  282.   if EOF(arcfile) then
  283.     endfile := TRUE
  284.   else
  285.     BlockRead(arcfile, arcbuf, 1, blocksRead);
  286.   arcptr := 1
  287. end; (* proc read_block *)
  288.  
  289. function open_arc:boolean;
  290. { open the archive file for input processing }
  291. var ok : boolean;
  292. begin
  293.   ok := SFGetReset(arcfile,BLOCKSIZE,'');
  294.   if ok then begin
  295.     arcname := SFDialog.r.fname;
  296.     endfile := FALSE;
  297.     Read_Block;
  298.     end
  299.   else begin
  300.     arcname := '';
  301.     endfile := TRUE;
  302.   end;
  303.   open_arc := ok;
  304. end; (* proc open_arc *)
  305.  
  306. function open_ext:Boolean;
  307. { open the extracted file for writing }
  308. begin
  309.   open_ext := SFPutRewrite(extfile,TextFile,extname);
  310.   extname := SFDialog.r.fname;
  311. end; (* proc open_ext *)
  312.  
  313. function get_arc : byte;
  314. { read 1 character from the archive file }
  315. begin
  316.   if endfile then
  317.     get_arc := 0
  318.   else begin
  319.     get_arc := arcbuf[arcptr];
  320.     if arcptr = BLOCKSIZE then
  321.       Read_Block
  322.     else
  323.       arcptr := succ(arcptr)
  324.   end
  325.     
  326. end; (* func get_arc *)
  327.  
  328. procedure put_ext(c : byte);
  329. { write 1 character to the extracted file }
  330. begin
  331.   write(extfile,char(c));
  332. end; (* proc put_ext *)
  333.  
  334. procedure close_arc;
  335. { close the archive file }
  336. begin
  337.   close(arcfile)
  338. end; (* proc close_arc *)
  339.  
  340. procedure close_ext;
  341. { close the extracted file }
  342. begin
  343.   close(extfile)
  344. end; (* proc close_ext *)
  345.  
  346. procedure fseek(offset : LongInt; base : integer);
  347. { re-position the current pointer in the archive file }
  348. var b           : LongInt;
  349.     i, ofs, rec : integer;
  350.     c           : byte;
  351. begin
  352.   case base of
  353.     0 : b := offset;
  354.     1 : b := offset + (FilePos(arcfile) - 1) * BLOCKSIZE
  355.               + arcptr - 1;
  356.     2 : b := offset + FileSize(arcfile) * BLOCKSIZE - 1
  357.     otherwise
  358.       abort('Invalid parameters to fseek')
  359.     end;
  360.   rec := b DIV BLOCKSIZE;
  361.   ofs := b - (rec * BLOCKSIZE);
  362.   seek(arcfile, rec);
  363.   Read_Block;
  364.   for i := 1 to ofs do
  365.     c := get_arc
  366. end; (* proc fseek *)
  367.  
  368. procedure fread(var buf; reclen : integer);
  369. { read a record from the archive file }
  370. type buftype = packed array [1..MaxInt] of byte;
  371. var i : integer;
  372.     b : ^buftype;
  373. begin
  374.   b := @buf;
  375.   if (reclen = SizeOf(Integer)) or (reclen = sizeof(LongInt)) then
  376.     for i := reclen downto 1 do {68000 integers are H,L}
  377.       b^[i] := get_arc          { 80xx integers are L,H}
  378.   else
  379.     for i := 1 to reclen do
  380.       b^[i] := get_arc;
  381. end; (* proc fread *)
  382.  
  383. function readhdr(var hdr : heads) : boolean;
  384. { read a file header from the archive file }
  385. { FALSE = eof found; TRUE = header found }
  386. label exit;
  387. var name : fntype;
  388.     try  : integer;
  389. begin
  390.   try := 10;
  391.   readhdr := FALSE;
  392.   if endfile then
  393.     goto exit ;              (******** was "exit" ************)
  394.     
  395.   while get_arc <> arcmarc do begin
  396.     if try = 0 then
  397.       abort(arcname + ' is not an archive');
  398.     try := try - 1;
  399.     writeln(arcname, ' is not an archive, or is out of sync');
  400.     if endfile then
  401.       abort('Archive length error')
  402.     end; (* while *)
  403.  
  404.   hdrver := get_arc;
  405.   if hdrver < 0 then
  406.     abort('Invalid header in archive ' + arcname);
  407.   if hdrver = 0 then   { special end of file marker }
  408.     goto exit;               (******** was "exit" ************)
  409.  
  410.   if hdrver > arcver then begin
  411.     fread(name, fnlen);
  412.     writeln('I dont know how to handle file ', fn_to_str(name),
  413.             ' in archive ', arcname);
  414.     writeln('I think you need a newer version of DEARC.');
  415.     halt;
  416.     end;
  417.  
  418.   fread(hdr.name,fnlen+1);
  419.   if hdrver = 1 then begin
  420.     fread(hdr.size, sizeof(heads) - sizeof(hdr.name) - sizeof(long));
  421.     hdrver := 2;
  422.     hdr.length := hdr.size
  423.     end
  424.   else
  425.     fread(hdr.size, sizeof(heads) - sizeof(hdr.name));
  426.  
  427.   readhdr := TRUE;
  428.  
  429.   {Convert to 68000 integers}
  430.     with hdr do begin
  431.       size  := long86(size);
  432.       date  :=  int86(date);
  433.       time  :=  int86(time);
  434.       crc   :=  int86(crc);
  435.       length:= long86(length);
  436.     end;
  437. exit:
  438. end; (* func readhdr *)
  439.  
  440. procedure putc_unp(c : integer);
  441. begin
  442.   crcval := ((crcval shr 8) and $00FF) xor crctab[(crcval xor c) and $00FF];
  443.   put_ext(c)
  444. end; (* proc putc_unp *)
  445.  
  446. procedure putc_ncr(c : integer);
  447. begin
  448.   case state of
  449.     NOHIST : if c = DLE then
  450.                state := INREP
  451.              else begin
  452.                lastc := c;
  453.                putc_unp(c)
  454.                end;
  455.     INREP  : begin
  456.              if c = 0 then
  457.                putc_unp(DLE)
  458.              else begin
  459.                c := c - 1;
  460.                while (c <> 0) do begin
  461.                  putc_unp(lastc);
  462.                  c := c - 1
  463.                  end
  464.                end;
  465.              state := NOHIST
  466.              end;
  467.     end; (* case *)
  468. end; (* proc putc_ncr *)
  469.  
  470. function getc_unp : integer;
  471. begin
  472.   if size = 0 then
  473.     getc_unp := -1
  474.   else begin
  475.     size := size - 1;
  476.     getc_unp := get_arc;
  477.     end;
  478. end; (* func getc_unp *)
  479.  
  480. procedure init_usq;
  481. { initialize for unsqueeze }
  482. var i : integer;
  483. begin
  484.   bpos := 99;
  485.   fread(numnodes, sizeof(numnodes));
  486.   if (numnodes < 0) or (numnodes > NUMVALS) then
  487.     abort('File has an invalid decode tree');
  488.   node[0].child[0] := -(SPEOF + 1);
  489.   node[0].child[1] := -(SPEOF + 1);
  490.   for i := 0 to numnodes-1 do begin
  491.     fread(node[i].child[0], sizeof(integer));
  492.     fread(node[i].child[1], sizeof(integer))
  493.     end;
  494. end; (* proc init_usq; *)
  495.  
  496. function getc_usq : integer;
  497. { unsqueeze }
  498. label exit;
  499. var i : integer;
  500. begin
  501.   i := 0;
  502.   while i >= 0 do begin
  503.     bpos := bpos + 1;
  504.     if bpos > 7 then begin
  505.       curin := getc_unp;
  506.       if curin = ERROR then begin
  507.         getc_usq := ERROR;
  508.         goto exit                   (******** was "exit" ************)
  509.         end;
  510.       bpos := 0;
  511.       i := node[i].child[1 and curin]
  512.       end
  513.     else begin
  514.       curin := curin shr 1;
  515.       i := node[i].child[1 and curin]
  516.       end
  517.     end; (* while *)
  518.   i := - (i + 1);
  519.   if i = SPEOF then
  520.     getc_usq := -1
  521.   else
  522.     getc_usq := i;
  523.   exit:
  524. end; (* func getc_usq *)
  525.  
  526. function h(pred, foll : integer) : integer; {MGB 87/02/28}
  527. { calculate hash value }
  528.   var Local,p,f: LongInt;
  529.   begin
  530.     p := BitAnd(pred,$FFFF);  f := BitAnd(foll,$FFFF);
  531.     if newhash then
  532.       Local := (p + f) * 15073
  533.     else begin
  534.       Local := BitOr(p + f, $0800);
  535.       Local := BitShift(Local*Local,-6);
  536.     end;
  537.     h := BitAnd(Local,$0FFF);
  538.   end; (* func h *)
  539.  
  540. function eolist(index : integer) : integer;
  541. var temp : integer;
  542. begin
  543.   temp := string_tab^[index].next;
  544.   while temp <> 0 do begin
  545.     index := temp;
  546.     temp := string_tab^[index].next
  547.     end;
  548.   eolist := index
  549. end; (* func eolist *)
  550.  
  551. function hash(pred, foll : integer) : integer;
  552. var local     : integer;
  553.     tempnext  : integer;
  554. begin
  555.   local := h(pred, foll);
  556.   if not string_tab^[local].used then
  557.     hash := local
  558.   else begin
  559.     local := eolist(local);
  560.     tempnext := (local + 101) and $0FFF;
  561.     while string_tab^[tempnext].used do begin
  562.       tempnext := tempnext + 1;
  563.       if tempnext = TABSIZE then
  564.         tempnext := 0
  565.       end;
  566.     string_tab^[local].next := tempnext;
  567.     hash := tempnext
  568.     end;
  569. end; (* func hash *)
  570.  
  571. procedure upd_tab(pred, foll : integer);
  572. begin
  573.   with string_tab^[hash(pred, foll)] do begin
  574.     used := TRUE;
  575.     next := 0;
  576.     predecessor := pred;
  577.     follower := lo(foll)
  578.     end
  579. end; (* proc upd_tab *)
  580.  
  581. function gocode : integer;
  582. label exit;
  583. var localbuf  : integer;
  584.     returnval : integer;
  585. begin
  586.   if inbuf = EMPTY then begin
  587.     localbuf := getc_unp;
  588.     if localbuf = -1 then begin
  589.       gocode := -1;
  590.       goto exit                       (******** was "exit" ************)
  591.       end;
  592.     localbuf := localbuf and $00FF;
  593.     inbuf := getc_unp;
  594.     if inbuf = -1 then begin
  595.       gocode := -1;
  596.       goto exit                       (******** was "exit" ************)
  597.       end;
  598.     inbuf := inbuf and $00FF;
  599.     returnval := ((localbuf shl 4) and $0FF0) + ((inbuf shr 4) and $000F);
  600.     inbuf := inbuf and $000F
  601.     end
  602.   else begin
  603.     localbuf := getc_unp;
  604.     if localbuf = -1 then begin
  605.       gocode := -1;
  606.       goto exit                       (******** was "exit" ************)
  607.       end;
  608.     localbuf := localbuf and $00FF;
  609.     returnval := localbuf + ((inbuf shl 8) and $0F00);
  610.     inbuf := EMPTY
  611.     end;
  612.   gocode := returnval;
  613. exit:
  614. end; (* func gocode *)
  615.  
  616. procedure push(c : integer);
  617. begin
  618.   stack[sp] := c;
  619.   sp := sp + 1;
  620.   if sp >= TABSIZE then
  621.     abort('Stack overflow')
  622. end; (* proc push *)
  623.  
  624. function pop : integer;
  625. begin
  626.   if sp > 0 then begin
  627.     sp := sp - 1;
  628.     pop := stack[sp]
  629.   end else
  630.     pop := EMPTY
  631. end; (* func pop *)
  632.  
  633. procedure init_tab;
  634. var i : integer;
  635. begin
  636.   FillChar(string_tab^, sizeof(string_tab^), 0);
  637.   for i := 0 to 255 do
  638.     upd_tab(NO_PRED, i);
  639.   inbuf := EMPTY;
  640.   { outbuf := EMPTY }
  641. end; (* proc init_tab *)
  642.  
  643. procedure init_ucr(i:integer);
  644. begin
  645.   newhash := i = 1;
  646.   sp := 0;
  647.   init_tab;
  648.   code_count := TABSIZE - 256;
  649.   firstc := TRUE
  650. end; (* proc init_ucr *)
  651.  
  652. function getc_ucr : integer;
  653. label exit;
  654. var c       : integer;
  655.     code    : integer;
  656.     newcode : integer;
  657. begin
  658.   if firstc then begin
  659.     firstc := FALSE;
  660.     oldcode := gocode;
  661.     finchar := string_tab^[oldcode].follower;
  662.     getc_ucr := finchar;
  663.     goto exit                         (******** was "exit" ************)
  664.     end;
  665.   if sp = 0 then begin
  666.     newcode := gocode;
  667.     code := newcode;
  668.     if code = -1 then begin
  669.       getc_ucr := -1;
  670.       goto exit                       (******** was "exit" ************)
  671.       end;
  672.     if not string_tab^[code].used then begin
  673.       code := oldcode;
  674.       push(finchar)
  675.       end;
  676.     while string_tab^[code].predecessor <> NO_PRED do
  677.       with string_tab^[code] do begin
  678.         push(follower);
  679.         code := predecessor
  680.         end;
  681.     finchar := string_tab^[code].follower;
  682.     push(finchar);
  683.     if code_count <> 0 then begin
  684.       upd_tab(oldcode, finchar);
  685.       code_count := code_count - 1
  686.       end;
  687.     oldcode := newcode
  688.     end;
  689.   getc_ucr := pop;
  690. exit:
  691. end; (* func getc_ucr *)
  692.  
  693. function getcode : integer;
  694. label
  695.   next, exit;
  696. var
  697.   code, r_off, bitsx : integer;        dummy:char;
  698.   bp : byte;
  699. begin
  700.   if firstch then
  701.   begin
  702.     offset := 0;
  703.     sizex := 0;
  704.     firstch := false;
  705.   end;
  706.   bp := 0;
  707.   if (clear_flg > 0) or (offset >= sizex) or (free_ent > maxcode) then
  708.   begin
  709.     if free_ent > maxcode then
  710.     begin
  711.       n_bits := n_bits + 1;
  712.       if n_bits = BITS then
  713.         maxcode := maxcodemax
  714.       else
  715.         maxcode := (1 shl n_bits) - 1;
  716.     end;
  717.     if clear_flg > 0 then
  718.     begin
  719.       n_bits := INIT_BITS;
  720.       maxcode := (1 shl n_bits) - 1;
  721.       clear_flg := 0;
  722.     end;
  723.     for sizex := 0 to n_bits-1 do
  724.     begin
  725.       code := getc_unp;
  726.       if code = -1 then
  727.         goto next
  728.       else
  729.         buf[sizex] := code;
  730.     end;
  731.     sizex := sizex + 1;
  732. next:
  733.     if sizex <= 0 then
  734.     begin
  735.       getcode := -1;
  736.       goto exit;
  737.     end;
  738.     offset := 0;
  739.     sizex := (sizex shl 3) - (n_bits - 1);
  740.   end;
  741.   r_off := offset;
  742.   bitsx := n_bits;
  743.  
  744.   { get first byte }
  745.   bp := lo(bp + (r_off shr 3));
  746.   r_off := r_off and 7;
  747.  
  748.   { get first parft (low order bits) }
  749.   code := buf[bp] shr r_off;
  750.   bp := bp + 1;
  751.   bitsx := bitsx - (8 - r_off);
  752.   r_off := 8 - r_off;
  753.  
  754.   if bitsx >= 8 then
  755.   begin
  756.     code := code or (buf[bp] shl r_off);
  757.     bp := bp + 1;
  758.     r_off := r_off + 8;
  759.     bitsx := bitsx - 8;
  760.   end;
  761.  
  762.   code := code or ((buf[bp] and rmask[bitsx]) shl r_off);
  763.   offset := offset + n_bits;
  764.   getcode := code;
  765. exit:
  766. end;
  767.  
  768. procedure decomp;
  769. label
  770.   next,exit;
  771. var
  772.   stackp,
  773.   finchar :integer;
  774.   code, oldcode, incode : integer;
  775.  
  776. begin
  777.   { INIT var }
  778.   if firstch then
  779.     maxcodemax := 1 shl bits;
  780.  
  781.   code := getc_unp;
  782.   if code <> BITS then
  783.   begin
  784.     abort('File packed with '+Num2String(code)+' bits, I can only handle '+Num2String(BITS));
  785.   end;
  786.   clear_flg := 0;
  787.  
  788.   n_bits := INIT_BITS;
  789.   maxcode := (1 shl n_bits ) - 1;
  790.   for code := 255 downto 0 do
  791.   begin
  792.     prefix^[code] := 0;
  793.     suffix^[code] := code;
  794.   end;
  795.  
  796.   free_ent := FIRST;
  797.   oldcode := getcode;
  798.   finchar := oldcode;
  799.   if oldcode = -1 then
  800.     goto exit;
  801.   putc_ncr(finchar);
  802.   stackp := 0;
  803.  
  804.   code := getcode;
  805.   while code  > -1 do
  806.   begin
  807.     if code = CLEAR then
  808.     begin
  809.       for code := 255 downto 0 do
  810.         prefix^[code] := 0;
  811.       clear_flg := 1;
  812.       free_ent := FIRST - 1;
  813.       code := getcode;
  814.       if code = -1 then
  815.         goto next;
  816.     end;
  817. next:
  818.     incode := code;
  819.     if code >= free_ent then
  820.     begin
  821.       stack1[stackp] := finchar;
  822.       stackp := stackp + 1;
  823.       code := oldcode;
  824.     end;
  825.     while code >= 256 do
  826.     begin
  827.       stack1[stackp] := suffix^[code];
  828.       stackp := stackp + 1;
  829.       code := prefix^[code];
  830.     end;
  831.     finchar := suffix^[code];
  832.     stack1[stackp] := finchar;
  833.     stackp := stackp + 1;
  834.     repeat
  835.       stackp := stackp - 1;
  836.       putc_ncr(stack1[stackp]);
  837.     until stackp <= 0;
  838.     code := free_ent;
  839.     if code < maxcodemax then
  840.     begin
  841.       prefix^[code] := oldcode;
  842.       suffix^[code] := finchar;
  843.       free_ent := code + 1;
  844.     end;
  845.     oldcode := incode;
  846.     code := getcode;
  847.   end;
  848. exit:
  849. end;
  850.  
  851. procedure unpack(var hdr : heads);
  852. label exit;
  853. var c : integer;
  854. begin
  855.   crcval := 0;
  856.   size := hdr.size;
  857.   state := NOHIST;
  858.   case hdrver of
  859.     1, 2 : begin
  860.            c := getc_unp;
  861.            while c <> -1 do begin
  862.              putc_unp(c);
  863.              c := getc_unp
  864.              end
  865.            end;
  866.     3    : begin
  867.            c := getc_unp;
  868.            while c <> -1 do begin
  869.              putc_ncr(c);
  870.              c := getc_unp
  871.              end
  872.            end;
  873.     4    : begin
  874.            init_usq;
  875.            c := getc_usq;
  876.            while c <> -1 do begin
  877.              putc_ncr(c);
  878.              c := getc_usq
  879.              end
  880.            end;
  881.     5    : begin
  882.            init_ucr(0);
  883.            c := getc_ucr;
  884.            while c <> -1 do begin
  885.              putc_unp(c);
  886.              c := getc_ucr
  887.              end
  888.            end;
  889.     6    : begin
  890.            init_ucr(0);
  891.            c := getc_ucr;
  892.            while c <> -1 do begin
  893.              putc_ncr(c);
  894.              c := getc_ucr
  895.              end
  896.            end;
  897.     7    : begin
  898.            init_ucr(1);
  899.            c := getc_ucr;
  900.            while c <> -1 do begin
  901.              putc_ncr(c);
  902.              c := getc_ucr
  903.              end
  904.            end;
  905.  
  906.     8    : begin
  907.              decomp;
  908.            end;
  909.     otherwise
  910.            writeln('I dont know how to unpack file ', fn_to_str(hdr.name));
  911.            writeln('I think you need a newer version of DEARC');
  912.            fseek(hdr.size, 1);
  913.            goto exit                         (******** was "exit" ************)
  914.     end; (* case *)
  915.   if crcval <> hdr.crc then
  916.     writeln('WARNING: File ', fn_to_str(hdr.name), ' fails CRC check');
  917. exit:
  918. end; (* proc unpack *)
  919.  
  920. procedure extract_file(var hdr : heads);
  921. begin
  922.   extname := fn_to_str(hdr.name);
  923.   if open_ext then begin
  924.     unpack(hdr);
  925.     close_ext
  926.     end
  927.   else 
  928.     fseek(hdr.size,1);
  929. end; (* proc extract *)
  930.  
  931. procedure extarc;
  932. var hdr : heads;
  933. begin
  934.   if open_arc then begin
  935.     while readhdr(hdr) do
  936.       extract_file(hdr);
  937.     close_arc
  938.     end
  939.   else begin
  940.     if FileErr<>noErr then
  941.       abort('Didn''t open ARC file. FileErr='+Num2String(FileErr));
  942.   end;
  943. end; (* proc extarc *)
  944.  
  945. procedure PrintHeading;
  946. begin
  947.   writeln;
  948.   writeln('Turbo Pascal DEARC Utility');
  949.   writeln('Version 2.0, 6/11/86');
  950.   writeln('Supports ARC version 5.12 files');
  951.   writeln;
  952. end; (* proc PrintHeading *)
  953.  
  954. procedure init_vars;
  955.   begin
  956.     init_crctab;
  957.     StuffIt(@RMASK,'000103070F1F3F7FFF');
  958.     New(string_tab);
  959.     New(prefix);
  960.     New(suffix);
  961.   end;
  962.  
  963. begin
  964.   init_vars;
  965.   firstch := true;
  966.   PrintHeading; { print a heading }
  967.   extarc;       { extract all files from the archive }
  968. end.